package com.ddone.sms.service.impl;

import com.ddone.common.exception.Assert;
import com.ddone.common.exception.BusinessException;
import com.ddone.common.result.ResponseEnum;
import com.ddone.common.util.HttpUtils;
import com.ddone.common.util.RandomUtils;
import com.ddone.common.util.RegexValidateUtils;
import com.ddone.sms.config.SmsProperties;
import com.ddone.sms.service.SmsService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author ddone
 * @date 2024/4/15-19:09
 */
@Service
@Slf4j
public class SmsServiceImpl implements SmsService {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void sendSms(String mobile, Integer type) {
        //1、手机号码格式校验：正则表达式
        Assert.isTrue(RegexValidateUtils.checkCellphone(mobile), ResponseEnum.MOBILE_ERROR);
        //2、手机号码发送频率： 、一天内只能获取5条
        String timeLimitKey = "sms:limit:" + type + ":" + mobile;
        Boolean hasTimeLimitKey = stringRedisTemplate.hasKey(timeLimitKey);
        Assert.isFalse(hasTimeLimitKey, ResponseEnum.ALIYUN_SMS_LIMIT_CONTROL_ERROR);
        String countLimitKey = "sms:count:" + type + ":" + mobile;
        if (stringRedisTemplate.hasKey(countLimitKey)) {
            Integer count = Integer.parseInt(stringRedisTemplate.opsForValue().get(countLimitKey));
            Assert.isFalse(count >= 5, ResponseEnum.ALIYUN_SMS_LIMIT_DAY_5);
        } else {
            stringRedisTemplate.opsForValue().set(countLimitKey, "0", 1, TimeUnit.DAYS);
        }
        // 3. 生成验证码发送短信
        String code = RandomUtils.getSixBitRandom();
        // sendMessage(mobile, code, 5);
        // 4、更新手机号码获取验证码的频率,缓存验证码 5分钟之内只能发送一次
        stringRedisTemplate.opsForValue().increment(countLimitKey);
        // 发送过一次后,需要等1分钟之后再发
        stringRedisTemplate.opsForValue().set(timeLimitKey,"1",1,TimeUnit.MINUTES);
        // 将验证码存入Redis, 5分钟之内有效
        String redisCodeKey = "sms:code:"+type+":"+mobile;
        stringRedisTemplate.opsForValue().set(redisCodeKey,code,5,TimeUnit.MINUTES);

    }

    /**
     * @param mobile    手机号
     * @param code      验证码
     * @param validTime 单位分钟
     */
    private void sendMessage(String mobile, String code, Integer validTime) {
        //服务器地址
        String host = SmsProperties.HOST;
        //资源路径
        String path = SmsProperties.PATH;
        //请求方式
        String method = SmsProperties.METHOD;
        //在短信平台购买短信服务时的 唯一id
        String appcode = SmsProperties.APP_CODE;
        Map<String, String> headers = new HashMap<>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //请求参数：
        Map<String, String> querys = new HashMap<>();
        //一般的短信平台：都是提供 短信模板id
        querys.put("mobile", mobile);
        querys.put("param", "**code**:" + code + "**minute**:" + validTime);
        //smsSignId（短信前缀）和templateId（短信模板），可登录国阳云控制台自助申请
        querys.put("smsSignId", "2e65b1bb3d054466b82f0c9d125465e2");
        querys.put("templateId", "908e94ccf08b4476ba6c876d13f084ad");
        Map<String, String> bodys = new HashMap<String, String>();
        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            String resultJson = EntityUtils.toString(response.getEntity(), "UTF-8");
            Map<String, String> map = objectMapper.readValue(resultJson, new TypeReference<Map<String, String>>() {
            });
            String resultCode = map.get("code");
            if (!"0".equals(resultCode)) {
                //短信发送失败
                System.out.println("短信发送失败，原因：" + resultJson);
                throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR);
            }
            //短信发送成功
            log.info("短信发送成功:" + resultJson);
        } catch (Exception e) {
            log.error("错误信息"+ ExceptionUtils.getStackTrace(e));
            throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR);
        }
    }
}
